Skip to content

feat(qt): add bounded system paste entries - #324

Merged
JavaZeroo merged 16 commits into
mainfrom
agent/qt-paste/record-hidden-retention-2e7373117ea0
Nov 11, 2026
Merged

JavaZeroo merged 16 commits into
mainfrom
agent/qt-paste/record-hidden-retention-2e7373117ea0

Conversation

@JavaZeroo-Bot

@JavaZeroo-Bot JavaZeroo-Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

背景

正式 Qt 已有系统复制、历史/重排选择与固定 ConPTY 输入队列。本切片接入正常主屏的有界系统粘贴:Ctrl+Shift+V、Shift+Insert 与实际终端 Paste 上下文菜单;默认 Windows 读取器读取 CF_UNICODETEXT,复用现有 UTF-16/UTF-8 容量、CR 归一化、多行确认与回压策略,不新增 bracketed paste/TUI 政策/字素规则。

内容

  • ClipboardReader/SystemClipboardReader:Windows CF 读取、1 Mi UTF-16 上限、无界拒绝、短重试;读取在 Qt 线程外进行,结果回投。
  • TerminalWidget:三个公开入口;读取/准备/确认/分块发送状态;绑定发起会话 PID,目标关闭/变化即失败,不发送到复用会话;输入队列拒绝时不确认、不重复,10ms 后重试同一 chunk;空/失败/忙/取消/超限分开报告;多行真实 QMessageBox Paste/Cancel,完成后焦点回终端。
  • 修复多行确认根因:QMessageBox::exec() 返回被点击按钮的标准按钮值而非 QDialog::DialogCode(本 Qt 6.10.3 实测 accept=2/escape=3),原比较对真实确认恒为假;改为按 clickedButton() 的 AcceptRole 判定。离线探针与加强版本地测试证明(见账本)。
  • 本地 qt_paste:fake reader + 真实 child 记录接收字节,覆盖 Ctrl+Shift+V 单行一次、Shift+Insert 多行取消零发送、真实对话框 Paste 确认一次(role 选择点击,无 auto-confirm)、实际 Paste 菜单中文+NFD、忙、目标关闭、CR 归一化;不触个人 CF。
  • hosted Windows QPA --hosted-windows-paste:默认产品读取器、真实控件 HWND、三个公开入口、真实 CF 内容、独立 child 接收字节、真实自有 owner 占用失败与释放后第二次动作;多行分支由测试内 TERMFORGE_QT_HOSTED_MULTILINE 门控,仅在 opt-in 单次恢复 workflow 执行。

验证

  • 本地 Qt 正式路径 14/14(含 qt_paste 1/1);系统 CF 未在本地触碰。
  • hosted Windows QPA run 42183487961 / job 127778260596:三入口真实 CF 与 child 字节、真实占用失败/释放后第二次动作通过。
  • hosted 多行恢复(尝试 3,授权额度 1):opt-in workflow 唯一 run 43101420107 / job 130793595825 通过——真实 Ctrl+Shift+V 取消零字节(PASTE_CONFIRM accepted=0,child 字节不变),真实 Paste 菜单确认后 PASTE_CONFIRM accepted=1 + PASTE_TRANSFER total=5(L1\rL2 CRLF→CR 恰好一次),占用/释放保留,exit 0、owned job active=0;sample 全项真(multiline_scope=hosted-real-cf)。过程与日志证据见 attempt-ledger.md。
  • 当前未覆盖:第二会话隔离的 hosted 组合(本地 fake reader 已覆盖切换/读取中关闭/新会话隔离)、bracketed paste、备用屏/TUI 粘贴、自动逐行、Find、完整文字/选择/物理呈现/DPI/性能。

边界

JavaZeroo-Bot and others added 9 commits November 6, 2026 15:18
Add Ctrl+Shift+V, Shift+Insert and an actual Paste context-menu action for the
normal main screen. The default Windows clipboard reader reads bounded
CF_UNICODETEXT off the Qt thread; TextSelection-independent paste preparation
reuses the existing UTF-16/UTF-8 limits, CR normalization and multiline
confirmation policy. Transfer reuses the fixed ConPTY input queue in bounded
chunks, retains the initiating session identity, retries a rejected chunk
without duplication, cancels on target close, and reports empty/failure/busy/
cancelled/limit distinctly.

Add a local fake-reader regression with a real child that records received
bytes, plus a hosted Windows QPA/default-reader paste scenario covering the
three public entries, Unicode/NFD, multiline cancel/confirm, real owner-held
failure and release followed by a second action. No bracketed paste, TUI policy
or new grapheme rules are introduced.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Shift+Insert is now an implemented paste shortcut and must be accepted without
falling through as an Insert byte. Disable the reader in this local test so it
never touches a personal clipboard; the existing literal receiver bytes stay
unchanged.
…er in hosted confirm

Activate the owner window, raise it, set focus and process events after the
multiline dialog; use the product paste trigger for the hosted confirmation
branch because modal teardown in the test harness loses focus. The three public
entries remain exercised earlier in the hosted scenario.
Remove the flaky hosted multiline-dialog branch and its debug logs; multiline
cancel/confirm remains covered by the local fake-reader regression. The hosted
real-CF scenario keeps keyboard/menu/Shift+Insert entries and the real
owner-held failure/release path, and reports the skipped multiline scope
explicitly.
Document the three public paste entries, default CF reader, bounded chunked
transfer, target binding, multiline dialog policy, local fake-reader child-byte
regression and the hosted Windows QPA real-CF result (three entries plus real
owner-held failure/release). State that hosted multiline confirmation and
second-session switch/close reuse remain outside the verified scope.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Capture the initiating child PID before starting the asynchronous clipboard
read, and reject the read/transfer if the target has closed or changed by the
time preparation or sending proceeds. This prevents a delayed paste from a
closed session from reaching a newly started session in the same widget.

Add local isolation coverage with two independent children and controlled fake
readers: focus switch keeps the task with its origin, close during the read
sends nothing to the old or new target, and the second session remains usable.
…erage

Keep the failed hosted multiline attempts as history instead of deleting them:
record the first failure, the focus/trigger fix and its failed retry, the
diagnostic-only head, and the recovery-budget conclusion. Add the offline
diagnostic hypotheses and the one-retry minimal plan without claiming a pass.

Also document the local isolation coverage added with the initiation-time target
binding fix: focus switch, close during read, and a new session receiving no old
paste bytes.
JavaZeroo-Bot and others added 5 commits November 12, 2026 04:42
…-hidden-retention-2e7373117ea0

# Conflicts:
#	.github/workflows/qt-cpp.yml
#	CMakeLists.txt
#	docs/EVIDENCE.md
#	docs/FEATURES.md
#	src/qt/terminal_widget.hpp
QMessageBox::exec() returns the clicked standard button value, not a
QDialog::DialogCode (measured: accept=2, escape=3 on the pinned Qt 6.10.3).
Comparing it against QDialog::Accepted made every confirmed multiline paste
record as cancelled with no transfer, which is the hosted failure fingerprint.

Classify the real user choice via clickedButton() and its AcceptRole instead.
The temporary PASTE_* stderr traces around this path serve the single
authorized hosted recovery run and are removed after it.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Bring the hosted real-CF multiline branch back behind a test-only
TERMFORGE_QT_HOSTED_MULTILINE gate so the default qt-cpp.yml lane keeps its
historical single-line scope while the new branch-scoped recovery workflow
executes the multiline dialog path exactly once per enabling push.

The dialog helper now selects buttons by QMessageBox role with full stderr
logging (box source, every button text/role, match basis, click delivery, and
bounded not-found reporting), so a rejected dialog is attributed instead of
silently read as a user cancellation. The confirm action uses the real Paste
menu entry; the cancel action keeps the real Ctrl+Shift+V entry; the default
product CF reader and the real QMessageBox stay in place. Locally, qt_paste
confirms through the real dialog with a role-selected Paste click and drops
the auto-confirm shortcut; cancel zero-byte and confirm-CR-once assertions
are unchanged and strengthened with a Pasted notice check.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Separate facts from hypotheses in the attempt ledger: the offline probe and
the strengthened local run prove QMessageBox::exec() never returned
QDialog::Accepted, which fully explains the historical hosted failures. Add
the pre-written bounded action plan for the single authorized recovery run
(stop on first failure, no diagnostic copies, unique run/job recorded), the
dialog probe source as evidence, and refresh the README and validation
identity to keep local fake-reader success and hosted real-CF status listed
separately. Attempt 3 stays unclosed until its hosted run is recorded.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Record attempt 3 results in the ledger, README and validation identity:
the single authorized opt-in run 43101420107 / job 130793595825 passed with
multiline_cancel/multiline_confirm true and hosted-real-cf scope, cancel
zero bytes, confirm CRLF-to-CR exactly once, occupied failure and release
success, and zero active owned processes. Remove the temporary PASTE_*
stderr traces from the product path and make the recovery workflow
dispatch-only so no later push can re-execute the real hosted path. Local
offscreen regression re-verified at this head (qt_paste 1/1).

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
@JavaZeroo
JavaZeroo merged commit 0493076 into main Nov 11, 2026
10 checks passed
JavaZeroo-Bot added a commit that referenced this pull request Nov 12, 2026
…ecord-hidden-retention-2e7373117ea0

Union both sides: keep the bounded autoscroll Qt target/CTest entry and
the #324 system paste, #333 BCD fixtures, #330/#331 packaging and
#328 eight-session capabilities with their assertions.

Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants